﻿using Heroius.Extension.WPF;
using Heroius.Files;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace Heroius.Cert
{
    /// <summary>
    /// 一次证书生成的配置
    /// </summary>
    [PropertyChanged.AddINotifyPropertyChangedInterface]
    public class CertInfo
    {
        /// <summary>
        /// 一次证书生成的配置
        /// </summary>
        public CertInfo() { }

        /// <summary>
        /// 生成位置
        /// </summary>
        [PropertyPanel(Label = "生成位置"), DataType("Folder"), EntitySilo]
        public string WorkingDirectory { get; set; }
        /// <summary>
        /// 当前生成的证书名(文件名，与字段无关)
        /// </summary>
        [PropertyPanel(Label = "证书名"), EntitySilo]
        public string CertId { get; set; } = "NewCert";
        /// <summary>
        /// 当前生成的证书级别
        /// </summary>
        [PropertyPanel(Order = -1), PropertyChanged.DoNotNotify]
        public CertLev Level
        {
            get
            {
                if (string.IsNullOrEmpty(IssuerId) && IsCA) return CertLev.Root;
                else if (IsCA) return CertLev.Intermediate;
                else return CertLev.EndUser;
            }
        }

        /// <summary>
        /// 颁发者的证书文件名
        /// </summary>
        [PropertyPanel(Label = "颁发者证书名", ToolTip = "在相同工作目录下，之前生成的CA证书名。留空则意味着自签名。"), EntitySilo]
        public string IssuerId { get; set; } = string.Empty;
        /// <summary>
        /// 是否创建CA证书
        /// </summary>
        [PropertyPanel(Label = "将此证书作为CA证书"), EntitySilo]
        public bool IsCA { get; set; } = false;


        /// <summary>
        /// 密钥位数
        /// </summary>
        [PropertyPanel(Label = "密钥位数", OptionsStore = "2048\r\n4096\r\n8192"), EntitySilo]
        public int KeyBits { get; set; } = 2048;
        /// <summary>
        /// 生成密钥时使用的加密密码
        /// </summary>
        [DataType(DataType.Password), PropertyPanel(Label = "密钥保护密码", ToolTip = "生成密钥时使用的，用于保护密钥的加密密码，若留空则密钥不加密保护"), EntitySilo]
        public string KeyPassphrase { get; set; } = string.Empty;

        /// <summary>
        /// 证书有效期
        /// </summary>
        [PropertyPanel(Label = "证书有效期", OptionsStore = "5\r\n30\r\n365\r\n3650\r\n7235", ToolTip = "天数的最大值为7235（约20年），超出将导致证书生成失败"), EntitySilo]
        public int Days { get; set; } = 5;

        /// <summary>
        /// field:国家，2字符
        /// </summary>
        [PropertyPanel(Label = "国家代码"), EntitySilo]
        public string CountryName { get; set; } = "CN";
        /// <summary>
        /// field：州/省
        /// </summary>
        [PropertyPanel(Label = "州省名"), EntitySilo]
        public string StateName { get; set; } = "LN";
        /// <summary>
        /// field: 城市名
        /// </summary>
        [PropertyPanel(Label = "城市名"), EntitySilo]
        public string CityName { get; set; } = "SY";
        /// <summary>
        /// field：组织名
        /// </summary>
        [PropertyPanel(Label = "组织名"), EntitySilo]
        public string OrgName { get; set; } = "EnvSafe";
        /// <summary>
        /// field：部门名
        /// </summary>
        [PropertyPanel(Label = "部门名"), EntitySilo]
        public string OrgUnitName { get; set; } = string.Empty;
        /// <summary>
        /// field：一般标识
        /// </summary>
        [PropertyPanel(Label = "一般名称标记"), EntitySilo]
        public string CommonName { get; set; } = "EnvSafe Test Cert";
        /// <summary>
        /// field：电子邮件
        /// </summary>
        [PropertyPanel(Label = "电子邮件"), EntitySilo]
        public string Email { get; set; } = string.Empty;

        /// <summary>
        /// extra attr:请求密码，CA 用于识别申请者身份的密码，附加在CSR中以备后用
        /// </summary>
        [DataType(DataType.Password), PropertyPanel(Label = "请求密码", ToolTip = "CA 用于识别申请者身份的密码，附加在CSR中以备后用"), EntitySilo]
        public string ChallengePassword { get; set; } = string.Empty;
        /// <summary>
        /// extra attr:
        /// </summary>
        [PropertyPanel(Label = "可选公司名"), EntitySilo]
        public string OptionalCoName { get; set; } = string.Empty;

        /// <summary>
        /// more:用于生成个人交换文件时提供导出密码
        /// </summary>
        [PropertyPanel(Label = "Pfx导出密码", ToolTip = "用于生成个人交换文件时提供导出密码，留空则不会生成pfx文件"), DataType(DataType.Password), EntitySilo]
        public string PfxExportPassword { get; set; } = string.Empty;

        [PropertyPanel(Label = "密钥用法"), EntitySilo, PropertyChanged.DoNotNotify]
        public ObservableCollection<KeyUsage> KeyUsages { get; set; } = new ObservableCollection<KeyUsage>();

        [PropertyPanel(Label = "增强密钥用法"), EntitySilo, PropertyChanged.DoNotNotify]
        public ObservableCollection<EnhancedKeyUsage> EnhancedKeyUsages { get; set; } = new ObservableCollection<EnhancedKeyUsage>();

        [PropertyPanel(Label = "别名"), EntitySilo, PropertyChanged.DoNotNotify]
        public ObservableCollection<string> AlterNames { get; set; } = new ObservableCollection<string>();

        [PropertyPanel(Label = "证书链"), EntitySilo, PropertyChanged.DoNotNotify]
        public ObservableCollection<string> Crls { get; set; } = new ObservableCollection<string>();

        [PropertyPanel(Label = "OCSP"), EntitySilo, PropertyChanged.DoNotNotify]
        public ObservableCollection<OCSPInfo> OCSP { get; set; } = new ObservableCollection<OCSPInfo>();
    }

    public class OCSPInfo
    {
        [EntitySilo]
        public string IssuerCert { get; set; } = string.Empty;
        [EntitySilo]
        public string OCSP { get; set; } = string.Empty;
    }

    /// <summary>
    /// 列举证书级别
    /// </summary>
    public enum CertLev
    {
        /// <summary>
        /// 根证书
        /// </summary>
        [Description("根证书")]
        Root,
        /// <summary>
        /// 中间证书
        /// </summary>
        [Description("中间证书")]
        Intermediate,
        /// <summary>
        /// 终端证书
        /// </summary>
        [Description("终端证书")]
        EndUser
    }

    /// <summary>
    /// 列举密钥用法
    /// </summary>
    public enum KeyUsage
    {
        /// <summary>
        /// Public key used only for enciphering data while performing key agreement
        /// <para>• Req. KeyUsage.KeyAgreement</para>
        /// </summary>
        [Description("仅加密")]
        EncipherOnly = 1,
        /// <summary>
        ///Subject public key is to verify signatures on revocation information, such as a CRL
        ///<para>• This extension must only be used for CA certificates</para>
        /// </summary>
        [Description("吊销列表签名")]
        CrlSign = 2,
        /// <summary>
        /// Subject public key is used to verify signatures on certificates
        /// <para>•	This extension must only be used for CA certificates</para>
        /// </summary>
        [Description("密钥证书签名")]
        KeyCertSign = 4,
        /// <summary>
        /// Certificate enables use of a key agreement protocol to establish a symmetric key with a target
        /// <para>Symmetric key may then be used to encrypt and decrypt data sent between the entities</para>
        /// </summary>
        [Description("密钥协商")]
        KeyAgreement = 8,
        /// <summary>
        /// Certificate may be used to encrypt & decrypt actual application data
        /// </summary>
        [Description("数据加密")]
        DataEncipherment = 16,
        /// <summary>
        /// Certificate may be used to encrypt a symmetric key which is then transferred to the target
        /// <para>Target decrypts key, subsequently using it to encrypt & decrypt data between the entities</para>
        /// </summary>
        [Description("密钥加密")]
        KeyEncipherment = 32,
        /// <summary>
        /// Certificate may be used to sign data as above but the certificate public key may be used to provide non-repudiation services
        /// <para>This prevents the signing entity from falsely denying some action</para>
        /// </summary>
        [Description("防抵赖")]
        NonRepudiation = 64,
        /// <summary>
        /// Certificate may be used to apply a digital signature
        /// <para>Digital signatures are often used for entity authentication and data origin authentication with integrity</para>
        /// </summary>
        [Description("数字签名")]
        DigitalSignature = 128,
        /// <summary>
        /// Public key used only for deciphering data while performing key agreement
        /// <para>• Req. KeyUsage.KeyAgreement</para>
        /// </summary>
        [Description("仅解密")]
        DecipherOnly = 32768
    }

    /// <summary>
    /// 增强型密钥用法
    /// </summary>
    public enum EnhancedKeyUsage
    {
        /// <summary>
        /// 相当于同时指定：ServerAuth, ClientAuth, CodeSigning, EmailProtection, TimeStamping, OCSPSigning
        /// </summary>
        [Description("全部")]
        AnyExtendedKeyUsage,
        /// <summary>
        /// All VPN clients must be signed with this EKU present 
        /// <para>SSL/TLS Web/VPN Client authentication EKU distinguishing a client as a client only</para>
        /// <para>Req. KU: digitalSignature and/or keyAgreement</para>
        /// </summary>
        [Description("客户端认证")]
        ClientAuth,
        /// <summary>
        /// Code Signing: Signing of downloadable executable code
        /// <para>Req. KU: digitalSignature, nonRepudiation, and/or keyEncipherment or keyAgreement</para>
        /// </summary>
        [Description("代码签名")]
        CodeSigning,
        /// <summary>
        /// Email Protection via S/MIME, allows you to send and receive encrypted emails 
        /// <para>Req. KU: digitalSignature, keyEncipherment or keyAgreement</para>
        /// </summary>
        [Description("邮件保护")]
        EmailProtection,
        /// <summary>
        /// •	RFC 4945: The use of these three EKU values is obsolete and explicitly deprecated by this specification [5.1.3.12]
        /// </summary>
        [Description("IPSec 终端系统")]
        IpsecEndSystem,
        /// <summary>
        /// •	RFC 4945: The use of these three EKU values is obsolete and explicitly deprecated by this specification [5.1.3.12]
        /// </summary>
        [Description("IPSec 通道")]
        IpsecTunnel,
        /// <summary>
        /// •	RFC 4945: The use of these three EKU values is obsolete and explicitly deprecated by this specification [5.1.3.12]
        /// </summary>
        [Description("IPSec 用户")]
        IpsecUser,
        /// <summary>
        /// OCSP Signing: Signing OCSP responses
        /// <para>Req. KU: digitalSignature, nonRepudiation</para>
        /// </summary>
        [Description("在线证书状态查询签名")]
        OcspSigning,
        /// <summary>
        /// All VPN servers should be signed with this EKU present 
        /// <para>SSL/TLS Web/VPN Server authentication EKU, distinguishing a server which clients can authenticate against</para>
        /// <para>This supersedes nscertype options (ns in nscertype stands for NetScape [browser])</para>
        /// <para>Req. KU: digitalSignature, keyEncipherment or keyAgreement</para>
        /// </summary>
        [Description("服务器认证")]
        ServerAuth,
        [Description("智能卡登录")]
        SmartCardLogon,
        /// <summary>
        /// Trusted Timestamping: Binding the hash of an object to a time
        /// <para>Req. KU: digitalSignature, nonRepudiation</para>
        /// </summary>
        [Description("时间戳")]
        TimeStamping,
        /// <summary>
        /// Microsoft Individual Code Signing (authenticode) 
        /// <para>Req. KU: digitalSignature, keyEncipherment or keyAgreement</para>
        /// </summary>
        [Description("微软个人代码签名")]
        MSCodeInd,
        /// <summary>
        /// Microsoft Commerical Code Signing (authenticode) 
        /// <para>Req. KU: digitalSignature, keyEncipherment or keyAgreement</para>
        /// </summary>
        [Description("微软商业代码签名")]
        MSCodeCom,
        /// <summary>
        /// Microsoft Trust List Signing 
        /// <para>Req. KU: digitalSignature, nonRepudiation</para>
        /// </summary>
        [Description("微软信任列表签名")]
        MSCTLSign,
        /// <summary>
        /// Microsoft Encrypted File System Signing 
        /// <para>Req. KU: digitalSignature, keyEncipherment or keyAgreement</para>
        /// </summary>
        [Description("微软加密文件系统签名")]
        MSEFS
    }
}
